/*
Copyright (c) [2019年5月1日] [吴超]
[MBT_studio] is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:
		 http://license.coscl.org.cn/MulanPSL2
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details.
*/
#include "stdafx.h"
#include "Widget.h"

#include <线性代数/几何计算.h>
#include <字符串数值互换.h>
#include <字符串/str_分割.h>
#include <文件/file_文件名数据.h>
#include <数据工具库.h>

#include <nmmintrin.h>
#include <ppl.h>
#include <ft2build.h>
#include <freetype.h>

#include "布局.h"



#include FT_FREETYPE_H



E_鼠标样式				C_Widget::g_鼠标样式 = E_鼠标样式::e_鼠标样式_默认;
S_鼠标					C_Widget::g_鼠标 = {};
int8					C_Widget::g_焦点数量 = 0;
bool					C_Widget::g_是否打开了弹出窗口 = false;
bool					C_Widget::G清除焦点组件 = false;
std::set<S_键位映射*>	C_Widget::G键位映射容器;


static vec4			g_当前窗口区域;

static C_Widget*	gTopWidget[64]	= {};
static uint8		gTopWidgetCount	= 0;

static uint16		g绘制变换ID		= 0;
static uint16		g绘制元素ID		= 0;
static uint16		g绘制图元ID		= 0;

static bool			g是否使用输入法 = false;
static bool			g输入法有输入 = false;
static ivec2		g输入法窗口位置 = {};
static std::wstring g输入法文本;
static int32		g输入法正在输入的字符;
//static std::wstring	g输入法正在输入的字符;


static std::set<S_关联组件*> g关联组件容器;


//C_Widget*	C_Widget管理::m_当前锁定焦点部件 = 0;
std::vector<std::wstring> C_Widget管理::m_拖放文件名;



uvec2		C_文本框::g_选择文本ID区间 = {};
vec2		C_文本框::g_光标绘制位置 = {};
C_文本框*	C_文本框::g当前操作文本框 = nullptr;




static void f_部件更新阶段回调() {
	
}


static S_需更新部件 f_get变换需修改部件(C_Widget* self) {
	return { self->m_子组件.data(), uint32(self->m_子组件.size()) };
}

static void f_set变换修改(struct C_Widget* self) {
	//mat3X2* 变换 = f_vg_map绘制数据指针<mat3X2>(self->m_画布, g绘制变换ID);
	//
	//变换[0].row0 = vec2{ float32(0), float32(0) };
	////(t[0])[0].row1 = vec2{ float32(self->m_裁剪大小.z - self->m_裁剪大小.x), float32(self->m_裁剪大小.w - self->m_裁剪大小.y) } -6;
	//变换[0].row1 = self->m_Size;
	////变换[0].row1 = {50, 50};
	//变换[0].row2 = { 1, 0 };
	//
	//f_vg_unmap绘制数据指针(self->m_画布, g绘制变换ID);
	//
	//f_vg_set图元(self->m_画布, g绘制图元ID, 0, S_Widget预设图元::m_矩形);
}

static void f_基本Draw(struct C_Widget* 部件, struct S_2D画布* 画布) {
	
	//g绘制变换ID = f_vg_gen变换(画布);
	//auto c = f_vg_gen颜色(画布);
	//auto p = f_vg_gen属性(画布);
	//g绘制图元ID = f_vg_gen图元(画布);
	//g绘制元素ID = f_vg_gen单色凸边形填充(画布, g绘制图元ID, g绘制变换ID, c, p);
	
	//f_vg_set单色(画布, c, 0, { 255,70,255, 120 });

	//f_vg_set实例数量(画布, 0, 1);
}






static bool f_鼠标按钮空事件(C_Widget* self, const E_鼠标按钮& 按钮) {
	return true;
}
static bool f_鼠标滚轮空事件(C_Widget* self, const S_鼠标& 轮值) {
	return true;
}
static bool f_鼠标移动空事件(C_Widget* self, const ivec4& value) {
	return true;
}
static bool f_鼠标进入空事件(C_Widget* self, const S_鼠标& 轮值) {
	std::cout << "f_鼠标进入空事件:" << self->m_TypeName << std::endl;
	return true;
}
static bool f_鼠标移除空事件(C_Widget* self, const S_鼠标& 轮值) {
	std::cout << "f_f_鼠标移除空事件" << self->m_TypeName << std::endl;
	return true;
}




static inline void f_Widget事件初始化(C_Widget* w) {
	w->mf_鼠标按键按下 = f_鼠标按钮空事件;
	w->mf_鼠标按键放开 = f_鼠标按钮空事件;
	w->mf_鼠标按键点击 = f_鼠标按钮空事件;
	w->mf_鼠标按键双击 = f_鼠标按钮空事件;
	w->mf_鼠标滚轮 = f_鼠标滚轮空事件;
	w->mf_鼠标移动 = f_鼠标移动空事件;

	w->mf_鼠标按键双击 = 0;

	w->mf_键盘按键敲击 = 0;

	w->mf_开始拖拽 = 0;
	w->mf_结束拖拽 = 0;
	w->mf_拖拽 = 0;

	w->mf_DrawFun = 0;
	w->mf_变换修改 = 0;
	w->mf_当前部件属性修改 = nullptr;
	w->mf_文件处理回调 = nullptr;

	w->mf_鼠标进入 = 0;
	w->mf_鼠标离开 = 0;

	w->mf_动画更新 = 0;
	w->mf_打开关闭 = 0;
	//w->mf_鼠标进入 = f_鼠标进入空事件;
	//w->mf_鼠标移除 = f_鼠标移除空事件;
}




C_Widget::C_Widget(S_UI创建环境* ctx) : mf_DrawFun(0), m_扩展视口属性(0), m_GM(nullptr) {
	m_被裁剪 = false;

	f_Widget事件初始化(this);
	mf_拖拽 = nullptr;
	m_关联组件 = nullptr;

	mf_get更新组件 = f_get变换需修改部件;

	

	mf_布局Fun = 0;

	
	
	m_子部件裁剪使用父裁剪区域 = false;
	//mf_绘制到屏幕 = 0;
	m_GPU参数重置 = true;
	m_绘制属性更新 = true;
	//m_是否重绘 = true;
	m_开启渲染 = true;
	m_引用画布 = false;
	m_显示 = true;

	m_延申比 = 1.0f;
	m_是否延展 = { 0,0 };
	m_间隔宽度 = 1;


	m_Pos = { 0.0f, 0.0f };
	m_GlobalLoc = { 0.0f, 0.0f };
	m_Size = { 10.0f, 10.0f };
	m_Scale = { 1.0f, 1.0f };
	m_裁剪大小 = { 0, 0, 30, 30 };
	
	m_OriginalPos = m_Pos * m_Scale;
	m_OriginalSize = m_Size * m_Scale;


	m_画布 = nullptr;
	m_父部件 = nullptr;
	m_DPI = 1;
	m_图元 = S_Widget预设图元::m_矩形;
	
	m_实例ID = 0;
	//m_GPU内存偏移 = 0;
	//m_GPU文本字符内存偏移 = 0;
	//m_GPU文本变换内存偏移 = 0;

	m_UIctx = ctx;
	//m_文本对象 = {};
	if (ctx) {
		m_画布 = f_surface_创建2D画布(0, ctx->m_Ctx);
		m_画布->m_调色板 = ctx->m_Mat;

		//mf_DrawFun = f_基本Draw;
		//mf_变换修改 = f_set变换修改;
	}
	else {
		m_子部件绘制区间 = 0;
	}


	m_PropUILink = nullptr;
}

C_Widget::~C_Widget() {
	uint32 num = m_子组件.size();
	auto data = m_子组件.data();
	for (uint32 i = 0; i < num; ++i) {
		delete data[i];
	}
	m_子组件.clear();


	if (m_画布 && !m_引用画布) {
		f_surface_释放2D画布(m_画布);
	}
	m_画布 = nullptr;
	//for (auto& e : m_键位映射) {
	//	free(e);
	//}
	m_键位映射.clear();
}

void C_Widget::f_setPos(vec2 pos) {
	m_绘制属性更新 = true;
	m_Pos = pos;
}
void C_Widget::f_setOriginalPos(vec2 pos) {
	m_绘制属性更新 = true;
	m_OriginalPos = pos;
	m_Pos = pos;
}
void C_Widget::f_setOriginalSize(vec2 size) {
	m_绘制属性更新 = true;
	m_OriginalSize = size;
	m_Size = size;
}

void C_Widget::f_setSize(vec2 size) {
	m_绘制属性更新 = true;
	//m_area.m128_f32[2] = m_Pos.m128_f32[0] + size.x;
	//m_area.m128_f32[3] = m_Pos.m128_f32[1] + size.y;
	m_裁剪大小 = { 0.0f,0.0f, size.x, size.y };

	m_Size = size;
}

void C_Widget::f_setMinSize(vec2 size) {
	m_绘制属性更新 = true;
	m_Size = m_Scale * size;
	m_MinSize = m_Scale * size;
	m_OriginalSize = size;
}





void C_Widget::f_setX(float32 x) {
	m_绘制属性更新 = true;
	m_Pos.x = x;
}

void C_Widget::f_setY(float32 y) {
	m_绘制属性更新 = true;
	m_Pos.y = y;
}

void C_Widget::f_setW(float32 w) {
	m_绘制属性更新 = true;
	m_Size.x = w;
	m_OriginalSize.x = w;
}

void C_Widget::f_setH(float32 h) {
	m_绘制属性更新 = true;
	m_Size.y = h;
}






vec2 C_Widget::f_getPos() const {
	return m_Pos;
}
vec2 C_Widget::f_getSize() const {
	return m_Size;
}
vec2 C_Widget::f_getOriginalPos() const {
	return m_OriginalPos;
}
vec2 C_Widget::f_getOriginalSize() const {
	return m_OriginalSize;
}

C_Widget管理* C_Widget::f_get窗口管理() {
	return m_GM;
}

S_需更新部件 C_Widget::f_get更新部件() {
	return { m_子组件.data(), uint32(m_子组件.size()) };
}

C_Widget* C_Widget::f_get子组件(uint32 id) {
	if (id < m_子组件.size()) {
		return m_子组件[id];
	}
	return nullptr;
}

void C_Widget::f_裁剪() { //const vec4& area
	//m_Size = m_OriginalSize * m_Scale;
	uint32 num = m_子组件.size();
	if (!num) return;
	auto p = m_子组件.data();

	vec4* arec = &m_裁剪大小;
	if (m_子部件裁剪使用父裁剪区域) {
		arec = &(m_父部件->m_裁剪大小);
	}

	/*for (uint32 i = 0; i < num; ++i) {
		f_widget_裁剪组件(m_GlobalLoc, *arec, p[i]);
	}
	return;*/

	uint32 拆分次数 = num / 8;
	uint32 多出次数 = num - 拆分次数*8;

	for (uint32 i = 0; i < 拆分次数; ++i) {
		f_widget_裁剪组件_avx(m_GlobalLoc, *arec, &(p[i*8]), 8);
	}
	if (多出次数) {
		f_widget_裁剪组件_avx(m_GlobalLoc, *arec, &(p[拆分次数 * 8]), 多出次数);
	}
}

void C_Widget::f_重置布局(const vec4& area) {

}




void f_widget_裁剪组件(const vec2& pos, const vec4& 裁剪area, C_Widget* w) {
	w->m_GlobalLoc = pos + w->m_Pos;

	float32 左边, 顶边, 右边, 底边;
	左边 = w->m_GlobalLoc.x;
	顶边 = w->m_GlobalLoc.y;
	右边 = w->m_Size.x;
	底边 = w->m_Size.y;

	右边 = 左边 + 右边;
	底边 = 顶边 + 底边;

	左边 = DEF_Max(左边, 裁剪area.x);
	右边 = DEF_Min(右边, 裁剪area.z);
	顶边 = DEF_Max(顶边, 裁剪area.y);
	底边 = DEF_Min(底边, 裁剪area.w);

	w->m_被裁剪 = false;
	if (左边 > 裁剪area.z || 顶边 > 裁剪area.w) {
		w->m_被裁剪 = true;
	}
	if (右边 < 裁剪area.x || 底边 < 裁剪area.y) {
		w->m_被裁剪 = true;
	}
	if (w->m_被裁剪 == false) {
		w->m_裁剪大小.x = 左边;
		w->m_裁剪大小.y = 顶边;
		w->m_裁剪大小.z = 右边;
		w->m_裁剪大小.w = 底边;
	}
}





void f_widget_裁剪组件_avx(const vec2& pos, const vec4& 裁剪area, C_Widget** ws, uint8 num) {
	//__m128 a = _mm_add_ps(m_area, area);
	auto 父级左边 = _mm256_set1_ps(裁剪area.x);
	auto 父级顶边 = _mm256_set1_ps(裁剪area.y);
	auto 父级右边 = _mm256_set1_ps(裁剪area.z);
	auto 父级底边 = _mm256_set1_ps(裁剪area.w);


	__m256 左边;
	__m256 顶边;
	__m256 右边;
	__m256 底边;

	for (uint32 i = 0; i < num; ++i) {
		ws[i]->m_GlobalLoc = pos + ws[i]->m_Pos;
		//ws[i]->m_GlobalLoc.x = pos.x + ws[i]->m_Pos.x;
		//ws[i]->m_GlobalLoc.y = pos.y + ws[i]->m_Pos.y;
		左边.m256_f32[i] = ws[i]->m_GlobalLoc.x;
		顶边.m256_f32[i] = ws[i]->m_GlobalLoc.y;

		右边.m256_f32[i] = ws[i]->m_Size.x;
		底边.m256_f32[i] = ws[i]->m_Size.y;
	}

	右边 = _mm256_add_ps(左边, 右边);
	底边 = _mm256_add_ps(顶边, 底边);


	左边 = _mm256_max_ps(左边, 父级左边);
	右边 = _mm256_min_ps(右边, 父级右边);

	顶边 = _mm256_max_ps(顶边, 父级顶边);
	底边 = _mm256_min_ps(底边, 父级底边);



	//auto 是否大于左边 = _mm256_cmp_ps(左边, 父级右边, _CMP_GE_OS);
	//auto 是否大于底边 = _mm256_cmp_ps(顶边, 父级底边, _CMP_LE_OQ);
	//左边大于父组件右边 或 顶边大于父组件底边
	auto H是否重叠 = _mm256_and_ps(_mm256_cmp_ps(左边, 父级右边, _CMP_GT_OS), _mm256_cmp_ps(顶边, 父级底边, _CMP_GT_OS));
	//右边是否小于父部件坐标 或 底边是否小于父布局顶边
	auto V是否重叠 = _mm256_and_ps(_mm256_cmp_ps(右边, 父级左边, _CMP_LT_OQ), _mm256_cmp_ps(底边, 父级顶边, _CMP_LT_OQ));
	H是否重叠 = _mm256_or_ps(H是否重叠, V是否重叠);

	auto 同轴向逆向H = _mm256_cmp_ps(右边, 左边, _CMP_LT_OQ);
	auto 同轴向逆向V = _mm256_cmp_ps(底边, 顶边, _CMP_LT_OQ);
	H是否重叠 = _mm256_or_ps(H是否重叠, 同轴向逆向H);
	H是否重叠 = _mm256_or_ps(H是否重叠, 同轴向逆向V);



	for (uint32 i = 0; i < num; ++i) {
		if (H是否重叠.m256_f32[i]) {
			ws[i]->m_被裁剪 = true;
			
		}
		else {
			ws[i]->m_被裁剪 = false;
			ws[i]->m_裁剪大小.x = 左边.m256_f32[i];
			ws[i]->m_裁剪大小.y = 顶边.m256_f32[i];
			ws[i]->m_裁剪大小.z = 右边.m256_f32[i];
			ws[i]->m_裁剪大小.w = 底边.m256_f32[i];

		}
	}
}

void f_widget_单个部件裁剪(C_Widget* w, const vec4& 父area, const vec2& 父全局坐标) {
	w->m_GlobalLoc = 父全局坐标 + w->m_Pos;

	vec2 右边底边 = w->m_GlobalLoc + w->m_Size;

	w->m_裁剪大小.x = DEF_Max(w->m_GlobalLoc.x, 父area.x);
	w->m_裁剪大小.z = DEF_Min(右边底边.x, 父area.z);

	w->m_裁剪大小.y = DEF_Max(w->m_GlobalLoc.y, 父area.y);
	w->m_裁剪大小.w = DEF_Min(右边底边.y, 父area.w);


	if (w->m_裁剪大小.x >= 父area.z || w->m_裁剪大小.y >= 父area.w) {
		w->m_被裁剪 = true;
	}
	if (w->m_裁剪大小.z <= 父area.x || w->m_裁剪大小.w <= 父area.y) {
		w->m_被裁剪 = true;
	}

	w->m_被裁剪 = false;
}

int8 f_widget_筛选焦点组件_avx(C_Widget** ws, uint8 num, const vec2& point) {
	auto 鼠标X = _mm256_set1_ps(point.x);
	auto 鼠标Y = _mm256_set1_ps(point.y);

	__m256 左边 = _mm256_set1_ps(0.0);
	__m256 顶边 = _mm256_set1_ps(0.0);
	__m256 右边 = _mm256_set1_ps(0.0);
	__m256 底边 = _mm256_set1_ps(0.0);

	for (uint32 i = 0; i < num; ++i) {
		左边.m256_f32[i] = ws[i]->m_裁剪大小.x;
		顶边.m256_f32[i] = ws[i]->m_裁剪大小.y;
		右边.m256_f32[i] = ws[i]->m_裁剪大小.z;
		底边.m256_f32[i] = ws[i]->m_裁剪大小.w;
	}

	//_mm256_cmp_ps(鼠标X, 右边, _CMP_LT_OQ);
	//_mm256_cmp_ps(鼠标Y, 底边, _CMP_LT_OQ);
	auto 
	在范围 = _mm256_and_ps(_mm256_cmp_ps(鼠标X, 左边, _CMP_GT_OS), _mm256_cmp_ps(鼠标Y, 顶边, _CMP_GT_OS));
	在范围 = _mm256_and_ps(_mm256_cmp_ps(鼠标X, 右边, _CMP_LT_OQ), 在范围);
	在范围 = _mm256_and_ps(_mm256_cmp_ps(鼠标Y, 底边, _CMP_LT_OQ), 在范围);

	for (uint32 i = 0; i < num; ++i) {
		if (在范围.m256_f32[i]) {
			return i;
		}
	}

	return -1;
}




static std::vector<S_部件添加列队> g待添加部件;
static std::vector<C_Widget*> g待销毁部件;


void f_widget_remove子部件(C_Widget* self, int32 s, int32 e, bool 即时销毁) {
	if(e < 0) e = self->m_子组件.size();

	std::vector<C_Widget*> 要销毁的组件;
	for (int32 i = s; i < e; ++i) {
		//self->f_销毁子组件(s);
		要销毁的组件.push_back(self->m_子组件[i]);
	}
	f_widget_push待销毁部件(要销毁的组件.data(), 要销毁的组件.size());
	self->m_子组件.erase(self->m_子组件.begin() + s, self->m_子组件.begin() + e);

	self->m_绘制属性更新 = true;
	C_Widget::g_焦点数量 = 0;

}

void f_widget_remove子部件(C_Widget* self, uint32* id, uint32 num, bool 即时销毁) {
	std::vector<C_Widget*>	删除部件(num);
	auto* 子部件	= self->m_子组件.data();
	uint32 末尾ID = self->m_子组件.size();

	//auto 删除部件 = f_DT_末尾删除法移除数据<C_Widget*>(子部件, 末尾ID, id, num);
	auto* data = 删除部件.data();

	for (uint32 i = 0; i < num; ++i) {
		--末尾ID;

		uint32 cid = id[i];

		bool 是否交换 = true;
		for (uint32 j = 0; j < num; ++j) {
			if (末尾ID == id[j]) {
				是否交换 = false;
				break;
			}
		}
		//C_Widget* w = 子部件[cid];
		data[i] = 子部件[cid];;

		if (是否交换) {
			子部件[cid] = 子部件[末尾ID];
			子部件[cid]->m_实例ID = data[i]->m_实例ID;
		}

	}

	
	self->m_子组件.erase(self->m_子组件.begin() + 末尾ID, self->m_子组件.end());
	if(即时销毁) f_widget_push待销毁部件(data, num);
}

void f_widget_remove子部件(C_Widget* self, std::vector<C_Widget*>& ws, bool 即时销毁) {
	for (auto it = self->m_子组件.begin(); ; ) {
		if (it == self->m_子组件.end()) {
			break;
		}

		bool 推进 = true;
		for (auto e : ws) {
			if (*it == e) {
				it = self->m_子组件.erase(it);
				推进 = false;
				break;
			}
		}
		
		if(推进) 
			++it;
	}

	if (即时销毁) {
		f_widget_push待销毁部件(ws.data(), ws.size());
	}
}

void f_widget_remove子部件(C_Widget* self, C_Widget** ws, uint32 num, bool 即时销毁) {
	/*self->m_子组件.push_back();

	if (即时销毁) {
		f_widget_push待销毁部件(ws.data(), ws.size());
	}*/
}

void f_widget_remove所有子部件(C_Widget* self, bool 即时销毁) {
	if (即时销毁) {
		for (auto& e : self->m_子组件) {
			delete e;
		}
	}
	else {
		f_widget_push待销毁部件(self->m_子组件.data(), self->m_子组件.size());
	}
	self->m_子组件.clear();
}



void f_widget_push待销毁部件(C_Widget** ws, uint32 num) {
	for (uint32 i = 0; i < num; ++i) {
		g待销毁部件.push_back(ws[i]);
	}
}

bool f_widget_待销毁部件清理() {
	//Concurrency::parallel_for_each(g待销毁部件.begin(), g待销毁部件.end(), [&](C_Widget* w) {
	//	delete w;
	//});
	uint32 num = g待销毁部件.size();
	for (uint32 i = 0; i < num; ++i) {
		delete g待销毁部件[i];
	}
	g待销毁部件.clear();

	return num;
}




void f_widget_push待添加部件(C_Widget* r, C_Widget** ws, uint32 num, int32 offset, bool 即时执行) {
	for (uint32 i = 0; i < num; ++i) {
		g待添加部件.push_back({r, ws[i], offset});
	}
	if (即时执行) {
		f_widget_执行待添加部件();
	}
}

void f_widget_push待添加部件(C_Widget* r, C_Widget* ws, int32 loc, bool 即时执行) {
	g待添加部件.push_back({ r, ws, loc });
	
	if (即时执行) {
		f_widget_执行待添加部件();
	}
}

void f_widget_执行待添加部件() {
	uint32 num = g待添加部件.size();

	for (uint32 i = 0; i < num; ++i) {
		auto& e = g待添加部件[i];

		e.m_rW->f_添加子组件(e.m_aW, e.m_Loc);
	}
	g待添加部件.clear();
}

void f_widget_添加子组件(C_Widget* self, std::vector<C_Widget*>& ws, bool 即时执行) {
	auto* wp = ws.data();
	uint32 num = ws.size();
	if (即时执行) {
		for (uint32 i = 0; i < num; ++i) {
			self->m_子组件.emplace_back(wp[i]);
		}
	}
	else {
		int32 offset = self->m_子组件.size();
		for (uint32 i = 0; i < num; ++i) {
			g待添加部件.push_back({ self, wp[i], offset });
		}
	}
}


void f_widget_关联组件(C_Widget* r, C_Widget* s) {
	if (r->m_关联组件 == nullptr) {
		r->m_关联组件 = (S_关联组件*)malloc(sizeof(S_关联组件));
		r->m_关联组件->m_W = r;
	}

	s->m_关联组件 = r->m_关联组件;
}


















void C_Widget::f_绘图(struct C_Widget* 画布, S_板载缓存* 投影矩阵) {

	if (m_画布) {
		if (m_画布->m_是否重绘 && mf_DrawFun) {
			f_begin绘制2D图形(m_画布);
			mf_DrawFun(this, m_画布);
			m_画布->m_是否重绘 = false;
			//goto To_GPU参数更新;
		}
	}

	uint32 sonNum = m_子组件.size();
	if (sonNum) {
		auto* p = m_子组件.data();
		for (uint32 i = 0; i < sonNum; ++i) {
			p[i]->f_绘图(this, 投影矩阵);
		}
	}
	
}

void C_Widget::f_添加子组件(C_Widget* w, int32 loc) {
	w->m_父部件 = this;
	
	if (loc > m_子组件.size() || loc < 0) {
		m_子组件.push_back(w);
	}
	else {
		m_子组件.insert(m_子组件.begin() + loc, w);
	}
	
	m_绘制属性更新 = true;
	m_GPU参数重置 = true;
}

void C_Widget::f_销毁子组件(int32 id) {
	if (id >= m_子组件.size()) {
		C_Widget* data[1] = { m_子组件.back() };
		f_widget_push待销毁部件(data, 1);
		
		m_子组件.pop_back();
	} else {
		C_Widget* data[1] = { m_子组件[id] };
		f_widget_push待销毁部件(data, 1);

		m_子组件.erase(m_子组件.begin()+id);
	}

	m_绘制属性更新 = true;
	C_Widget::g_焦点数量 = 0;
}

void C_Widget::f_替换子组件(int32 id, C_Widget* w) {
	w->m_GlobalLoc = m_子组件[id]->m_GlobalLoc;
	w->m_裁剪大小 = m_子组件[id]->m_裁剪大小;
	w->m_Size = m_子组件[id]->m_Size;
	w->m_Pos = m_子组件[id]->m_Pos;
	m_子组件[id] = w;

	w->m_父部件 = this;

	m_绘制属性更新 = true;
	w->m_GPU参数重置 = true;
}



void C_Widget::f_属性更新() {
	if (m_绘制属性更新 && m_画布) {

	}
}

void C_Widget::f_绑定窗口管理(C_Widget管理* gm) {
	m_GM = gm;
}










static S_材质* gUI单色绘制材质 = 0;


C_Widget管理::C_Widget管理(S_UI创建环境& Ctx): m_UICtx(&Ctx) {
	m_投影矩阵 = f_buf_create板载缓存(m_UICtx->m_Ctx, sizeof(Mat44f), E_板载缓存类型::e_UBO);

	std::vector<Mat44f> mat(1);
	f_fill板载缓存(m_投影矩阵, mat, E_板载缓存类型::e_UBO, m_UICtx->m_Ctx);

	m_视口GPU参数设置 = f_gpu_创建参数布局(m_投影矩阵, 0, E_着色阶段::e_顶点着色 | E_着色阶段::e_几何着色 | E_着色阶段::e_像素着色 | E_着色阶段::e_计算着色);



	mf_输入执行前回调 = f_部件更新阶段回调;
	mf_输入执行后回调 = f_部件更新阶段回调;

	//鼠标左键状态 = DEF_按键状态_准备;
	//鼠标中键状态 = DEF_按键状态_准备;
	//鼠标右键状态 = DEF_按键状态_准备;
	for (uint8 k = 0; k < 8; ++k) {
		鼠标按键状态[k] = DEF_按键状态_准备;
	}
	拖放状态 = DEF_拖放状态_准备;


	m_上一次焦点组件数量 = 0;
	for (uint8 i = 0; i < 128; ++i) {
		m_上一次焦点组件[i] = nullptr;
		m_焦点组件[i] = nullptr;
	}

	mui_窗口 = nullptr;
	有输入事件 = false;

	m_当前拖拽部件 = nullptr;
	m_当前操作部件 = nullptr;
}






void C_Widget管理::f_绘制子组件(C_Widget* self, S_渲染参数 参数) {
	if (self->m_开启渲染) {
		if (self->m_父部件 && self->m_父部件->m_扩展视口属性) {
			((S_Viewport*)参数.m_视口)->x = self->m_父部件->m_GlobalLoc.x;
			((S_Viewport*)参数.m_视口)->y = self->m_父部件->m_GlobalLoc.y;

			((S_Rect2D*)参数.m_裁剪)->offset.x = self->m_父部件->m_裁剪大小.x;
			((S_Rect2D*)参数.m_裁剪)->offset.y = self->m_父部件->m_裁剪大小.y;

			((S_Rect2D*)参数.m_裁剪)->extent.x = (self->m_父部件->m_裁剪大小.z - self->m_父部件->m_裁剪大小.x);
			((S_Rect2D*)参数.m_裁剪)->extent.y = (self->m_父部件->m_裁剪大小.w - self->m_父部件->m_裁剪大小.y);

		}
		else {
			((S_Viewport*)参数.m_视口)->x = self->m_GlobalLoc.x;
			((S_Viewport*)参数.m_视口)->y = self->m_GlobalLoc.y;

			((S_Rect2D*)参数.m_裁剪)->offset.x = self->m_裁剪大小.x;
			((S_Rect2D*)参数.m_裁剪)->offset.y = self->m_裁剪大小.y;

			((S_Rect2D*)参数.m_裁剪)->extent.x = (self->m_裁剪大小.z - self->m_裁剪大小.x);
			((S_Rect2D*)参数.m_裁剪)->extent.y = (self->m_裁剪大小.w - self->m_裁剪大小.y);
		}

		if (self->m_画布) {
			self->m_画布->f_绘制到屏幕(参数);
			self->m_显示 = true;
		}

		uint32 sonNum = self->m_子组件.size();
		if (sonNum) {
			auto* p = self->m_子组件.data();

	//#pragma omp parallel for
			for (int32 i = 0; i < sonNum; ++i) {
				if (p[i]->m_被裁剪 == false) {
					f_绘制子组件(p[i], 参数);
				}
			}
		}
	}
}





void C_Widget管理::f_加载图标(std::string 组名称, std::string path) {
	if (m_UICtx->m_Mat->m_ICOs.find(组名称) == m_UICtx->m_Mat->m_ICOs.end()) {
		m_UICtx->m_Mat->m_ICOs[组名称] = S_TexArrayRes();

		std::vector<std::string> 目录文件名;
		uint32 num = f_file_get目录下所有文件(path, 目录文件名);

		if (num > 0) {
			auto& tex = m_UICtx->m_Mat->m_ICOs[组名称];
			
			tex.m_Tex = f_fromFile创建纹理数组(m_UICtx->m_Ctx, m_UICtx->m_Mat->m_采样器, 目录文件名);
			for (uint32 i = 0; i < num; ++i) {
				tex.m_Name[f_file_取无后缀文件名(目录文件名[i])] = i;
			}
		}
		return;
	}

	assert(0);
}













uint8 f_widget_弹出顶层窗口(C_Widget* w) {
	gTopWidget[gTopWidgetCount] = w;
	return ++gTopWidgetCount;
}

uint8 f_widget_顶层窗口_push(C_Widget* w, uint8 offset) {
	gTopWidget[offset] = w;
	gTopWidgetCount = offset + 1;
	return gTopWidgetCount;
}

uint8 f_widget_顶层窗口_pop() {
	if (gTopWidgetCount > 0) {
		gTopWidget[--gTopWidgetCount] = 0;
	}
	return gTopWidgetCount;
}

uint8 f_widget_顶层窗口_pop(uint8 num) {
	if (num) {
		if (num < gTopWidgetCount) {
			gTopWidgetCount = num;
		}
	}
	else {
		gTopWidgetCount = 0;
	}
	return 0;
}

S_需更新部件 f_widget_getTop() {
	return { gTopWidget, gTopWidgetCount };
}

C_Widget* f_widget_getBack() {
	if (gTopWidgetCount > 0) {
		return gTopWidget[--gTopWidgetCount];
	}
	return nullptr;
}

uint8 f_widget_getTopNum() {
	return gTopWidgetCount;
}





void f_widget_remove子部件(C_Widget* self, uint32* id, bool 即时销毁)
{
}

void f_Widget_计算视口缩放保持偏移比例(C_Widget* self) {
	
	vec2 大小差 = vec_sub(self->m_扩展视口属性->m_大小, self->m_Size);
	vec_mul(&大小差, 0.5f);
	vec_sub(&self->m_扩展视口属性->m_中心, 大小差);

	self->m_扩展视口属性->m_大小 = self->m_Size;
	//std::cout << "W == " << 大小差.x << " = " << self->m_扩展视口属性->m_偏移比例.x << " : " << 偏移.x << std::endl;
}

//void f_widget_执行待添加部件(C_Widget* self, std::vector<>) {
//}

void f_Widget_视口偏移(C_Widget* self, float32 x, float32 y) {
	self->m_扩展视口属性->m_中心.x += x;
	self->m_扩展视口属性->m_中心.y += y;

	f_Widget_计算偏移比例(self);
}

void f_widget_clear焦点组件() {
	C_Widget::g_焦点数量 = 0;
}

uint32 f_widget_取组件位置索引(C_Widget* self, C_Widget* 要查找的组件) {
	auto e = self->f_get更新部件();
	for (uint32 i = 0; i < e.m_Num; ++i) {
		if(e.m_W[i] == 要查找的组件) return i;
	}
	return -1;
}

void f_widget_移动层(C_Widget* self, uint32 源组件位置索引, uint32 目标位置索引) {
	auto e = self->f_get更新部件();
	if(源组件位置索引 > 目标位置索引 && 目标位置索引 < e.m_Num) return;

	C_Widget* 源组件 = e.m_W[源组件位置索引];
	self->m_子组件.erase(self->m_子组件.begin() + 源组件位置索引);
	self->m_子组件.insert(self->m_子组件.begin() + 目标位置索引, 源组件);
}



void f_Widget_应用视口滚动(C_Widget* self, C_Widget* view, E_方向 方向) {
	if (方向 == E_方向::e_纵向) {
		
		
		float32 y = view->m_Pos.y;
		if (y > 0) {
			view->f_setY(0);
		} 
		else if (self->m_父部件 && view->m_Size.y + y < self->m_父部件->m_Size.y) {
			//if (y + view->m_Size.y < self->m_Size.y) {
				//view->f_setY(DEF_Min(self->m_Size.y - view->m_Size.y, 0));
			view->f_setY(-(self->m_Size.y - self->m_父部件->m_Size.y));
			//}
		}

		view->f_setY(view->m_Pos.y + C_Widget::g_鼠标.lZ * 30);
		//std::cout << "view->m_Pos.y == " << y << " " << view->m_Size.y << "  " << self->m_Size.y << std::endl;
	}
	
	view->m_绘制属性更新 = true;
}

void f_Widget_限定视口滚动(C_Widget* self, float32 父组件大小, float32* view, E_方向 方向, float32 s) {
	self->m_绘制属性更新 = true;

	if (方向 == E_方向::e_纵向) {
		//父组件大小 -= s;
		if (self->m_Size.y + (*view) <= 父组件大小) {
			//if (y + view->m_Size.y < self->m_Size.y) {
			(*view) = -(self->m_Size.y - 父组件大小);
			//return;
		}

		//(*view) += C_Widget::g_鼠标.lZ * s;

		if ((*view) > 0) {
			(*view) = 0;
		}
		//std::cout << "view->m_Pos.y == " << y << " " << view->m_Size.y << "  " << self->m_Size.y << std::endl;
	}
}




















vec2 f_widget_取鼠标在后光标位置(C_文本框* self, const vec2& 鼠标位置, E_对齐方式 对齐方式, vec2 offset, const std::wstring& text) {
	vec2 选框;
	uint16 文字索引位置 = 0;

	选框.x = 鼠标位置.x;
	选框.y = 文字索引位置;
	float32 光标位移 = offset.x;
	
	uint32 num = text.size();
	switch (对齐方式) {
		case E_对齐方式::e_左对齐:
		{
			float32 width = 0;
			for (uint32 i = 0; i < num; ++i) {
				width = f_surface_get字符串宽度(*self->m_字体, text[i], S_UI主题::ui_文字间隔);
				if (鼠标位置.x > 光标位移 + width * 0.5f) {
					文字索引位置 = i;

					
				} else {
					break;
				}
				光标位移 += width;
			}
			
			//if (num && 鼠标位置.x + width * 0.5f > 光标位移) {
			//	++文字索引位置;
			//}
		}
		break;
		case E_对齐方式::e_据中对齐:
		{
			float32 width = 0;
			for (uint32 i = 0; i < num; ++i) {
				width = f_surface_get字符串宽度(*self->m_字体, text[i], S_UI主题::ui_文字间隔);
				if (鼠标位置.x > 光标位移 + width * 0.5) {
					文字索引位置 = i;
				}
				else {
					break;
				}

				光标位移 += width;
			}

			//if (num && 鼠标位置.x + width * 0.5f > 光标位移) {
			//	++文字索引位置;
			//}
		}
		break;
		default:
			break;
	}
	//auto i = f_surface_get字符串宽度(字体, L"unti", S_UI主题::ui_文字间隔);
	选框.x = 光标位移;
	选框.y = 文字索引位置;

	return 选框;
}

vec2 f_widget_取鼠标在前光标位置(C_文本框* self, const vec2& 鼠标位置, E_对齐方式 对齐方式, vec2 offset, const std::wstring& text) {
	vec2 选框;
	int32 文字索引位置 = -1;

	选框.x = 鼠标位置.x;
	选框.y = 文字索引位置;
	float32 光标位移 = offset.x;
	
	uint32 num = text.size();
	switch (对齐方式) {
	case E_对齐方式::e_左对齐:
	{
		float32 width = 0;
		for (uint32 i = 0; i < num; ++i) {
			width = f_surface_get字符串宽度(*self->m_字体, text[i], S_UI主题::ui_文字间隔);
			if (鼠标位置.x > 光标位移 + width*0.5) {
				文字索引位置 = i;
			}
			else {
				//std::cout << "文字索引位置 = " << 文字索引位置 << std::endl;
				break;
			}

			光标位移 += width;
		}

		//if (num && 鼠标位置.x > 光标位移) {
		//	++文字索引位置;
		//}
	}
	break;
	case E_对齐方式::e_据中对齐:
	{
		for (uint32 i = 0; i < num; ++i) {
			float32 width = f_surface_get字符串宽度(*self->m_字体, text[i], S_UI主题::ui_文字间隔);
			if (鼠标位置.x > 光标位移 + width * 0.5) {
				文字索引位置 = i;
			}
			else {
				break;
			}
			光标位移 += width;
		}
	}
	break;
	default:
		break;
	}
	//auto i = f_surface_get字符串宽度(字体, L"unti", S_UI主题::ui_文字间隔);
	选框.x = 光标位移;
	选框.y = 文字索引位置;

	return 选框;
}

void f_widget_选择编辑文本(C_文本框* self, const uvec2& 区间) {
	//S_文本选框 选框;
	uint16 文字索引位置 = 0;

	//选框.x = 光标位置.x;
	//选框.y = offset.y;
	float32 光标位移 = 0;

	uint32 num = self->m_Text.size();
	switch (self->m_对齐方式) {
		case E_对齐方式::e_左对齐:
		{
			/*for (uint32 i = 0; i < num; ++i) {
				float32 width = f_surface_get字符串宽度(字体, text[1], S_UI主题::ui_文字间隔);
				if (光标位置.x > 光标位移 + width * 0.5) {
					文字索引位置 = i + 1;

					光标位移 += width;
				} else {
					break;
				}

			}

			选框.x = 光标位移;*/
		}
		break;
		case E_对齐方式::e_据中对齐:
		{
			float32 width = f_surface_get字符串宽度(*self->m_字体, self->m_Text, S_UI主题::ui_文字间隔);

			self->m_行选框左边和右边.x = (self->m_Size.x - width) * 0.5f;
			self->m_行选框左边和右边.y = self->m_行选框左边和右边.x;


			num = DEF_Min(区间.y, num);

			self->g_选择文本ID区间.x = 区间.x;
			self->g_选择文本ID区间.y = num;
			for (uint32 i = 区间.x; i < num; ++i) {
				float32 width = f_surface_get字符串宽度(*self->m_字体, self->m_Text[i], S_UI主题::ui_文字间隔);

				if (i < 区间.x) {
					self->m_行选框左边和右边.x += width;
					self->m_行选框左边和右边.y += width;
				}
				else {
					self->m_行选框左边和右边.y += width;
				}
			}

		}
		break;
		default:
			break;
	}
	
}























bool on_文本框鼠标点击(C_Widget* self, const E_鼠标按钮& 按钮) {
	C_文本框* editBox = dynamic_cast<C_文本框*>(self);

	if (C_文本框::g当前操作文本框 && C_文本框::g当前操作文本框 != editBox) {
		C_文本框::g当前操作文本框->f_输入完成();
	}

	editBox->f_开启输入();
	C_文本框::g当前操作文本框 = editBox;
	//std::cout << "on_文本框鼠标点击" << std::endl;
	return true;
}

C_文本框::C_文本框(S_UI创建环境& ctx, std::string 字体名称) : C_Widget(&ctx), m_选择开启(false), m_字体(&f_surface_get字体(ctx, 字体名称)) {
	//m_字行距 = m_字体->m_字号;
	mf_文本输入 = nullptr;
	mf_文本过滤 = nullptr;
	//mf_文本输入中 = nullptr;
	mf_文本输入完成 = nullptr;

	mf_鼠标按键点击 = on_文本框鼠标点击;

	m_对齐方式 = E_对齐方式::e_据中对齐;

	//m_光标位置 = {};
	m_光标 = {};
	m_选取 = {};

	m_字行距 = 4 * ctx.m_DPI;
	m_字间距 = 2 * ctx.m_DPI;

	m_文字边间距.x = 10 * ctx.m_DPI;
	m_文字边间距.y = 2 * ctx.m_DPI;

	m_选取.结束行列 = m_选取.开始行列 = { -1,-1 };

	m_文档 = &m_内部文档;
	f_setSize({ 512,256 });
	m_颜色A = S_UI主题::uic_行编辑框背景;
	m_颜色B = S_UI主题::uic_行编辑框背景;
}

C_文本框::~C_文本框() {
}

void C_文本框::f_开启输入() {
	C_文本框::g当前操作文本框 = this;

	f_set光标();

	//m_选取.开始行列 = { int32(m_光标.x) , int32(m_光标.y) };
	//m_选取.结束行列 = m_选取.开始行列;

	m_开启编辑 = true;
}

void C_文本框::f_输入完成() {
	m_开启编辑 = false;
	m_行选框左边和右边 = { 0,0 };
	if (mf_文本输入完成) mf_文本输入完成(this);
	//std::cout << "mf_文本输入完成 = " << mf_文本输入完成 << std::endl;
	C_文本框::g当前操作文本框 = nullptr;
	m_选取.开始行列 = {};
	m_选取.结束行列 = {};

	m_绘制属性更新 = true;
}

void C_文本框::f_set光标绘制坐标() {
	if (m_对齐方式 == E_对齐方式::e_据中对齐) {
		C_文本框::g_光标绘制位置 = f_widget_get文字绘制据中偏移(this, m_Text, *m_字体, S_UI主题::ui_文字间隔);
		if (m_光标.x == -1) {
		}
		else {
			C_文本框::g_光标绘制位置.x += f_surface_get字符串宽度(*m_字体, m_Text.substr(0, m_光标.x + 1), S_UI主题::ui_文字间隔);
		}
	}
	else {
		if (m_光标.x == -1) {
			C_文本框::g_光标绘制位置.x = m_文本对齐偏移.x;
		}
		else {
			C_文本框::g_光标绘制位置.x = f_surface_get字符串宽度(*m_字体, m_Text.substr(0, m_光标.x + 1), S_UI主题::ui_文字间隔) + m_文本对齐偏移.x;
		}
	}
}


void C_文本框::f_set文本(const std::wstring& text) {
	m_Text = text;
	m_光标.x = text.size();

	f_set对齐偏移();
	
	m_绘制属性更新 = true;
}

void C_文本框::f_set对齐偏移() {
	float32 width = 0;
	/*const auto& 字体 = f_surface_get字体库(*m_UIctx, S_UI主题::ui_默认字体);

	switch (m_对齐方式) {
		case E_对齐方式::e_左对齐:
			m_文本对齐偏移 = f_widget_get文字左对齐偏移位置(m_Size, m_Text, 字体, S_UI主题::ui_文字间隔);
			width = 0;
			break;

		case E_对齐方式::e_据中对齐:
			width = f_surface_get字符串宽度(*m_字体, m_Text, S_UI主题::ui_文字间隔);
			width = (m_Size.x - width) * 0.5;
			break;
	}
	//vec2 鼠标位置 = f_从全局坐标取局部坐标(C_Widget::g_鼠标.gPos, self);
	m_文本对齐偏移.x = width;
	m_文本对齐偏移.y = m_UIctx->m_DPI * 4;*/
	//m_光标位置.x = f_surface_get字符串宽度(*m_字体, m_Text.substr(0, C_文本框::g_选择区间.x), S_UI主题::ui_文字间隔) + m_文本边偏移.x;
}

S_文本前后 C_文本框::f_get当前输入前后字符() {
	S_文本前后 前后 = {};


	int32 IDx = m_光标.x - 1;
	int32 IDy = m_光标.y;
	if (IDx < 0) {
		--IDy;
		if (IDy >= 0) {
			if (m_文档->m_文本块[IDy].size()) {
				前后.前 = m_文档->m_文本块[IDy].back();
			}
		}
	}
	else {
		if (IDx < m_文档->m_文本块[IDy].size()) {
			前后.前 = m_文档->m_文本块[IDy][IDx];
		}
		else {
			前后.前 = m_文档->m_文本块[IDy].back();
		}
	}

	IDx = m_光标.x + 1;
	IDy = m_光标.y;
	if (IDx >= m_文档->m_文本块[IDy].size()) {
		if (IDy < m_文档->m_文本块.size()) {
			前后.后 = f_str_从跳过字符取字符(m_文档->m_文本块[IDy], L"\n ");
			//前后.后 = m_文档->m_文本块[IDy][0];
		}
		else {
			++IDy;
			if (m_文档->m_文本块[IDy].size()) {
				前后.后 = f_str_从跳过字符取字符(m_文档->m_文本块[IDy], L"\n ");
			}
		}
	}
	else {
		前后.后 = m_文档->m_文本块[IDy][IDx];
	}

	return 前后;
}

wchar_t C_文本框::f_get行头字符(int32 行) {
	if (行 < m_文档->m_文本块.size()) {
		if(m_文档->m_文本块[行].size()) return m_文档->m_文本块[行].front();
	}
	return 0;
}

wchar_t C_文本框::f_get行尾字符(int32 行) {
	if (行 < m_文档->m_文本块.size()) {
		if (m_文档->m_文本块[行].size()) return m_文档->m_文本块[行].back();
	}
	return 0;
}

uint32 C_文本框::f_get同样字符数量(int32 行, int32 offset, wchar_t txt) {
	uint32 num = 0;
	if (行 < m_文档->m_文本块.size()) {
		
		for (auto e : m_文档->m_文本块[行]) {
			if (e != txt) return num;
			++num;
		}
	}
	return num;
}










/*void f_ui_set鼠标样式(E_鼠标样式 样式) {
	HCURSOR 光标 = LoadCursor(NULL, IDC_SIZENWSE);

	HWND hwnd = GetForegroundWindow();
	SetClassLong(hwnd, -12, (long)光标);
}*/



void f_widget_开始输入法() {
	g是否使用输入法 = true;
	//g输入法输入字符数量 = 0;
}

void f_widget_结束输入法() {
	g是否使用输入法 = false;
	//g输入法输入字符数量 = 0;
	g输入法文本.clear();
}

void f_widget_结束输入状态() {
	if(!g是否使用输入法) g输入法有输入 = false;
}

bool f_widget_输入法是否有输入() {
	if(g输入法正在输入的字符 == 2 || g输入法正在输入的字符 == 1) --g输入法正在输入的字符;
	return g输入法有输入 && g输入法正在输入的字符 > 0;
}

ivec2 f_widget_get输入法窗口位置() {
	g是否使用输入法 = true;
	g输入法有输入 = true;
	return g输入法窗口位置;
}

void f_widget_发射输入法文本(const std::wstring& str) {
	g输入法文本 = str;
}

void f_widget_set编辑框输入法窗口位置(const ivec2& pos) {
	g输入法窗口位置 = pos;
}

std::wstring f_widget_get输入法文本() {
	std::wstring t = g输入法文本;
	//if(g输入法文本.size()) g输入法输入字符数量 = 0;
	g输入法文本.clear();
	g输入法正在输入的字符 = 0;
	return t;
}

bool f_widget_是否处在输入法状态() {
	return g是否使用输入法;
}

void f_widget_set当前正在输入的文本(const std::wstring& txt) {
	g输入法正在输入的字符 = txt.size();
}



void f_widget_set当前窗口矩形(const vec4& 区域) {
	g_当前窗口区域 = 区域;
}

vec4 f_widget_get当前窗口矩形() {
	return g_当前窗口区域;
}

void f_widget_交换顶层组件(C_Widget管理* gm, uint32 新顶层组件ID) {
	if (gm->m_Root->mf_打开关闭) gm->m_Root->mf_打开关闭(gm->m_Root, false);
	gm->m_Root = gm->m_根部件切换组[新顶层组件ID];
	if (gm->m_Root->mf_打开关闭) gm->m_Root->mf_打开关闭(gm->m_Root, true);
}

void f_widget_交换顶层组件(C_Widget* w, uint32 新顶层组件ID) {
	auto* gm = w->f_get窗口管理();
	if (gm) {
		if (gm->m_Root->mf_打开关闭) gm->m_Root->mf_打开关闭(gm->m_Root, false);
		gm->m_Root = gm->m_根部件切换组[新顶层组件ID];
		if (gm->m_Root->mf_打开关闭) gm->m_Root->mf_打开关闭(gm->m_Root, true);
	}
}

void f_widget_移除组件链接(C_Widget* self) {
	if (self->m_PropUILink && self->m_PropUILink->m_LinkWidget) {
		self->m_PropUILink->m_LinkWidget->erase(self);
	}
}

void f_widget_移除组件链接(std::vector<C_Widget*>& self) {
	for (auto& e : self) f_widget_移除组件链接(e);
}

void f_widget_属性链接组件(S_Props& prop, const std::vector<C_Widget*>& ws) {
	if(!prop.m_UI->m_LinkWidget) prop.m_UI->m_LinkWidget = new std::set<struct C_Widget*>();

	for (auto& e : ws) {
		(*prop.m_UI->m_LinkWidget).insert(e);
	}
}

void f_widget_属性断开组件(S_Props& prop, const std::vector<C_Widget*>& ws) {
	if (!prop.m_UI->m_LinkWidget) return;

	for (auto& e : ws) {
		(*prop.m_UI->m_LinkWidget).erase(e);
	}
}




static int32 g定时改变时长 = 600;
DWORD WINAPI f_widget_定时关闭弹出组件(LPVOID pParam) {
	int i = 0;

	Sleep(g定时改变时长);
	if (C_Widget::g_是否打开了弹出窗口) {
		C_Widget::g_是否打开了弹出窗口 = false;
		f_widget_顶层窗口_pop(0);
	}

	return 0;
}

void f_widget_线程定时关闭弹出组件(int32 延时) {
	g定时改变时长 = 延时;
	C_Widget::g_是否打开了弹出窗口 = true;
	auto hThread = CreateThread(NULL, 0, f_widget_定时关闭弹出组件, NULL, 0, NULL);
}

void f_widget_取消定时关闭弹出组件() {
	C_Widget::g_是否打开了弹出窗口 = false;
}


void f_widget_set鼠标位置(const vec2* pos){
	SetCursorPos(pos->x, pos->y);
}
















//std::map<S_键位映射*, S_Props> C_键位映射配置::g_全局键位映射容器;
//std::map<S_键位映射*, S_Props> C_键位映射配置::g_3D视口键位映射容器;
//std::map<S_键位映射*, S_Props> C_键位映射配置::g_2D视口键位映射容器;
//std::map<S_键位映射*, S_Props> C_键位映射配置::g_节点视口键位映射容器;
//
//
//
//void f_配置_添加操作键位(S_键位映射* key, uint32 分组) {
//	//g_全局键位映射容器.insert(key);
//}
//
//
//S_键位映射* f_配置_取操作键位(uint32 分组) {
//
//	return nullptr;
//}
//
//C_键位映射配置::C_键位映射配置()
//{
//}
//
//void C_键位映射配置::f_添加全局操作键位(S_键位映射* key, std::wstring name) {
//	if (g_全局键位映射容器.find(key) == g_全局键位映射容器.end()) {
//		S_Props prop = f_alloc_键位(key, name);
//
//		g_全局键位映射容器[key] = prop;
//		//f_ui_注册全局快捷键(key);
//	}
//}
//
//void C_键位映射配置::f_添加3D视口操作键位(S_键位映射* key, std::wstring name) {
//	if (g_3D视口键位映射容器.find(key) == g_3D视口键位映射容器.end()) {
//		S_Props prop = f_alloc_键位(key, name);
//
//		g_3D视口键位映射容器[key] = prop;
//	}
//}
//
//void C_键位映射配置::f_添加2D视口操作键位(S_键位映射* key, std::wstring name) {
//	if (g_2D视口键位映射容器.find(key) == g_2D视口键位映射容器.end()) {
//		S_Props prop = f_alloc_键位(key, name);
//
//		g_2D视口键位映射容器[key] = prop;
//	}
//}
//
//void C_键位映射配置::f_添加节点视口操作键位(S_键位映射* key, std::wstring name) {
//	if (g_节点视口键位映射容器.find(key) == g_节点视口键位映射容器.end()) {
//		S_Props prop = f_alloc_键位(key, name);
//
//		g_节点视口键位映射容器[key] = prop;
//	}
//}
//
//void C_键位映射配置::f_销毁键位映射() {
//	for (auto& e : g_全局键位映射容器) {
//		free(e.first);
//	}
//	g_全局键位映射容器.clear();
//
//	for (auto& e : g_全局键位映射容器) {
//		free(e.first);
//	}
//	g_全局键位映射容器.clear();
//}






